﻿using DevExpress.ExpressApp.Blazor.Components;
using DevExpress.ExpressApp.Blazor.Components.Models;
using DevExpress.ExpressApp.Blazor.Services;
using EasyXaf.DynamicForm.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using System.ComponentModel;

namespace EasyXaf.DynamicForm.Blazor.Components;

public abstract class FieldComponent : ComponentBase, IDisposable
{
    protected ComponentModelBase Model { get; set; }

    [Parameter]
    public Field Field { get; set; }

    [Parameter]
    public bool Inline { get; set; }

    [Parameter]
    public IDictionary<string, object> Data { get; set; }

    [Parameter]
    public EventCallback ValueChanged { get; set; }

    [Inject]
    protected IImageUrlService ImageUrlService { get; set; }

    private void OnComponentValueChanged(object sender, HandleValueEventArgs e)
    {
        if (!Data.TryGetValue(Field.Name, out object value) || !Equals(value, e.Value))
        {
            Data[Field.Name] = e.Value;
        }

        if (!Inline)
        {
            ValueChanged.InvokeAsync();
        }
    }

    private void OnDataPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (Model is IHandleValueComponentModel model)
        {
            if (e.PropertyName == Field.Name && !Equals(model.Value, Data[Field.Name]))
            {
                model.Value = ConvertValue(Data[Field.Name]);
            }
        }
    }

    protected abstract ComponentModelBase CreateComponentModel();

    protected virtual object ConvertValue(object value) => value;

    protected override void OnInitialized()
    {
        base.OnInitialized();

        Model = CreateComponentModel();

        if (!Inline && Model is DxComponentModelBase componentModel)
        {
            componentModel.ReadOnly = Field.IsCurrentlyReadOnly || Field.IsCalculated;
        }

        if (Model is IHandleValueComponentModel handleValueComponentModel)
        {
            if (Data.TryGetValue(Field.Name, out var value))
            {
                handleValueComponentModel.Value = ConvertValue(value);
            }

            handleValueComponentModel.ValueChanged += OnComponentValueChanged;
        }

        if (!Inline && Data is INotifyPropertyChanged data)
        {
            data.PropertyChanged += OnDataPropertyChanged;
        }
    }

    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        if (Model != null)
        {
            builder.AddContent(0, ComponentModelObserver.Create(Model, Model.GetComponentContent()));
        }
    }

    public virtual void Dispose()
    {
        if (Model is IHandleValueComponentModel model)
        {
            model.ValueChanged -= OnComponentValueChanged;
        }

        if (Data is INotifyPropertyChanged data)
        {
            data.PropertyChanged -= OnDataPropertyChanged;
        }

        GC.SuppressFinalize(this);
    }
}
